<!DOCTYPE
html >
  <html>
<head>
    <meta charset="UTF-8">
    <title>剪映关键帧工具</title>
    <style>
        :root {
            --bg-primary: #121212;
            --bg-secondary: #1e1e1e;
            --bg-tertiary: #2d2d2d;
            --bg-card: #252525;
            --text-primary: #e0e0e0;
            --text-secondary: #a0a0a0;
            --accent-primary: #7c4dff;
            --accent-secondary: #5e35b1;
            --success: #4caf50;
            --success-dark: #388e3c;
            --danger: #f44336;
            --danger-dark: #d32f2f;
            --warning: #ff9800;
            --border-color: #444;
            --input-bg: #333;
            --border-radius: 8px;
            --transition: all 0.3s ease;
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', 'Roboto', sans-serif;
            background-color: var(--bg-primary);
            color: var(--text-primary);
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
            font-size: 14px;
        }
        
        .main-container {
            background-color: var(--bg-secondary);
            padding: 25px;
            border-radius: var(--border-radius);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            width: 95%;
            max-width: 900px;
            margin-bottom: 20px;
        }
        
        h1 {
            color: var(--accent-primary);
            text-align: center;
            margin-bottom: 25px;
            font-size: 1.8em;
        }
        
        .file-selection-area,
        .effect-type-group,
        .params-area-wrapper,
        .checkbox-control-group,
        .action-buttons {
            margin-bottom: 25px;
        }
        
        /* File Selection */
        .file-selection-area label {
            display: block;
            margin-bottom: 8px;
            color: var(--text-primary);
        }
        
        #file-info {
            margin-top: 8px;
            font-style: italic;
            color: var(--text-secondary);
            font-size: 0.9em;
        }
        
        #file-info.selected {
            color: var(--accent-primary);
        }
        
        /* Effect Type Selection */
        .effect-type-group .control-label {
            display: block;
            margin-bottom: 10px;
            font-size: 1.1em;
            color: var(--text-primary);
        }
        
        .effect-type-group .radio-group {
            display: flex;
            flex-wrap: wrap;
            gap: 20px;
            align-items: center;
        }
        
        .effect-type-group .radio-group div {
            display: flex;
            align-items: center;
        }
        
        .effect-type-group .radio-group label {
            font-weight: normal;
            margin-left: 5px;
            margin-bottom: 0;
            white-space: nowrap;
            color: var(--text-secondary);
        }
        
        .effect-type-group .radio-group input[type="radio"] {
            accent-color: var(--accent-primary);
            margin: 0;
        }
        
        /* Parameter Sections */
        .param-section {
            border: 1px solid var(--border-color);
            padding: 20px;
            border-radius: var(--border-radius);
            background-color: var(--bg-card);
            margin-top: 15px;
        }
        
        .param-section h3 {
            margin-top: 0;
            margin-bottom: 20px;
            color: var(--accent-primary);
            font-size: 1.2em;
            border-bottom: 1px solid var(--border-color);
            padding-bottom: 10px;
        }
        
        /* Parameter Layout */
        .param-flex-container {
            display: flex;
            flex-wrap: wrap;
            gap: 15px 25px;
            align-items: flex-end;
        }
        
        /* Input Groups */
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 5px;
            min-width: 110px;
        }
        
        .input-group label {
            font-weight: normal;
            font-size: 0.9em;
            color: var(--text-secondary);
            margin-bottom: 0;
            white-space: nowrap;
        }
        
        .input-group input[type="number"] {
            width: 100px;
            padding: 8px;
            border: 1px solid var(--border-color);
            border-radius: 4px;
            box-sizing: border-box;
            font-size: 1em;
            background-color: var(--input-bg);
            color: var(--text-primary);
        }
        
        /* Percentage Sign */
        .input-group.scale-group {
            position: relative;
            padding-right: 15px;
        }
        
        .input-group.scale-group::after {
            content: '%';
            position: absolute;
            right: 0px;
            bottom: 10px;
            color: var(--text-secondary);
            font-size: 1em;
        }
        
        /* Buttons */
        button {
            padding: 10px 18px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 1em;
            transition: var(--transition);
            margin-right: 10px;
            min-width: 120px;
        }
        
        .primary-button { 
            background-color: var(--accent-primary); 
            color: white; 
        }
        
        .primary-button:hover { 
            background-color: var(--accent-secondary); 
        }
        
        .primary-button:disabled {
            background-color: var(--bg-tertiary);
            color: var(--text-secondary);
            cursor: not-allowed;
        }
        
        .secondary-button { 
            background-color: var(--bg-tertiary); 
            color: var(--text-primary); 
            border: 1px solid var(--border-color);
        }
        
        .secondary-button:hover { 
            background-color: var(--bg-card); 
        }
        
        .danger-button { 
            background-color: var(--danger); 
            color: white; 
        }
        
        .danger-button:hover { 
            background-color: var(--danger-dark); 
        }
        
        .danger-button:disabled {
            background-color: var(--bg-tertiary);
            color: var(--text-secondary);
            cursor: not-allowed;
        }
        
        .action-buttons { 
            text-align: center; 
        }
        
        .action-buttons button:last-child { 
            margin-right: 0; 
        }
        
        /* Checkbox */
        .checkbox-control-group label {
            display: flex;
            align-items: center;
            font-weight: normal;
            color: var(--text-secondary);
        }
        
        .checkbox-control-group input[type="checkbox"] {
            margin-right: 8px;
            accent-color: var(--accent-primary);
        }
        
        /* Status Area */
        #status {
            margin-top: 0;
            padding: 15px;
            background-color: var(--bg-tertiary);
            border: 1px solid var(--border-color);
            border-radius: var(--border-radius);
            width: 100%;
            min-height: 40px;
            text-align: center;
            color: var(--text-secondary);
            box-sizing: border-box;
            overflow-wrap: break-word;
        }
        
        /* Status States */
        .status-error {
            background-color: rgba(244, 67, 54, 0.2) !important;
            color: #ff8a80 !important;
        }
        
        .status-success {
            background-color: rgba(76, 175, 80, 0.2) !important;
            color: #a5d6a7 !important;
        }
        
        .status-processing {
            animation: pulse 1.5s infinite;
        }
        
        @keyframes pulse {
            0% { opacity: 0.6; }
            50% { opacity: 1; }
            100% { opacity: 0.6; }
        }
        
        /* Utility */
        .hidden { 
            display: none !important; 
        }
    </style>
</head>
<body>
    <div class="main-container">
        <h1>剪映关键帧工具</h1>
        
        <div class="file-selection-area">
            <label for="select-file-button">剪映草稿目录:</label>
            <button id="select-file-button" class="secondary-button">选择目录...</button>
            <div id="file-info">未选择目录</div>
        </div>

        <div class="effect-type-group">
            <label class="control-label">效果类型:</label>
            <div class="radio-group">
                <div>
                    <input type="radio" id="radio-random" name="effect-type" value="random" checked>
                    <label for="radio-random">随机</label>
                </div>
                <div>
                    <input type="radio" id="radio-top-bottom" name="effect-type" value="top_bottom">
                    <label for="radio-top-bottom">上下移动</label>
                </div>
                <div>
                    <input type="radio" id="radio-left-right" name="effect-type" value="left_right">
                    <label for="radio-left-right">左右移动</label>
                </div>
                <div>
                    <input type="radio" id="radio-zoom" name="effect-type" value="zoom">
                    <label for="radio-zoom">缩放</label>
                </div>
            </div>
        </div>

        <div class="params-area-wrapper">
            <div id="params-zoom" class="param-section hidden">
                <h3>缩放参数</h3>
                <div class="param-flex-container">
                    <div class="input-group scale-group">
                        <label for="zoom-scale">缩放倍数:</label>
                        <input type="number" id="zoom-scale" value="120" min="1">
                    </div>
                </div>
            </div>
    
            <div id="params-top-bottom" class="param-section hidden">
                <h3>上下移动参数</h3>
                <div class="param-flex-container">
                    <div class="input-group scale-group">
                        <label for="tb-scale">缩放倍数:</label>
                        <input type="number" id="tb-scale" value="120" min="1">
                    </div>
                    <div class="input-group">
                        <label for="tb-y1">上起始位置:</label>
                        <input type="number" id="tb-y1" value="240">
                    </div>
                    <div class="input-group">
                        <label for="tb-y2">下结束位置:</label>
                        <input type="number" id="tb-y2" value="-240">
                    </div>
                </div>
            </div>
    
            <div id="params-left-right" class="param-section hidden">
                <h3>左右移动参数</h3>
                <div class="param-flex-container">
                    <div class="input-group scale-group">
                        <label for="lr-scale">缩放倍数:</label>
                        <input type="number" id="lr-scale" value="120" min="1">
                    </div>
                    <div class="input-group">
                        <label for="lr-x1">左起始位置:</label>
                        <input type="number" id="lr-x1" value="240">
                    </div>
                    <div class="input-group">
                        <label for="lr-x2">右结束位置:</label>
                        <input type="number" id="lr-x2" value="-240">
                    </div>
                </div>
            </div>
            
            <div id="params-random" class="param-section">
                <h3>随机移动参数</h3>
                <div class="param-flex-container">
                    <div class="input-group scale-group">
                        <label for="rand-scale">缩放倍数:</label>
                        <input type="number" id="rand-scale" value="120" min="1">
                    </div>
                    <div class="input-group">
                        <label for="rand-x1">左起始位置:</label>
                        <input type="number" id="rand-x1" value="240">
                    </div>
                    <div class="input-group">
                        <label for="rand-x2">右结束位置:</label>
                        <input type="number" id="rand-x2" value="-240">
                    </div>
                    <div class="input-group">
                        <label for="rand-y1">上起始位置:</label>
                        <input type="number" id="rand-y1" value="240">
                    </div>
                    <div class="input-group">
                        <label for="rand-y2">下结束位置:</label>
                        <input type="number" id="rand-y2" value="-240">
                    </div>
                </div>
            </div>
        </div>
        
        <div class="checkbox-control-group">
            <label class="checkbox-label">
                <input type="checkbox" id="align-audio-image">
                音频图片对齐 (图片轨道1, 音频轨道2)
            </label>
        </div>

        <div class="action-buttons">
            <button id="apply-keyframes-button" class="primary-button">一键关键帧</button>
            <button id="delete-keyframes-button" class="danger-button">删除所有关键帧</button>
        </div>
    </div>

    <div id="status" class="main-container">请选择剪映草稿目录并设置参数。</div>

    <script>
        let draftFilePath = null;

        const selectFileButton = document.getElementById('select-file-button');
        const fileInfo = document.getElementById('file-info');
        const statusDiv = document.getElementById('status');
        
        const applyButton = document.getElementById('apply-keyframes-button');
        const deleteButton = document.getElementById('delete-keyframes-button');
        const alignAudioImageCheckbox = document.getElementById('align-audio-image');

        const effectTypeRadios = document.querySelectorAll('input[name="effect-type"]');
        const paramSections = {
            zoom: document.getElementById('params-zoom'),
            top_bottom: document.getElementById('params-top-bottom'),
            left_right: document.getElementById('params-left-right'),
            random: document.getElementById('params-random')
        };

        const zoomScaleInput = document.getElementById('zoom-scale');
        const tbScaleInput = document.getElementById('tb-scale');
        const tbY1Input = document.getElementById('tb-y1');
        const tbY2Input = document.getElementById('tb-y2');
        const lrScaleInput = document.getElementById('lr-scale');
        const lrX1Input = document.getElementById('lr-x1');
        const lrX2Input = document.getElementById('lr-x2');
        const randScaleInput = document.getElementById('rand-scale');
        const randX1Input = document.getElementById('rand-x1');
        const randX2Input = document.getElementById('rand-x2');
        const randY1Input = document.getElementById('rand-y1');
        const randY2Input = document.getElementById('rand-y2');

        function updateStatus(message, isError = false, isProcessing = false, isSuccess = false) {
            statusDiv.textContent = message;
            
            // Reset all status classes
            statusDiv.classList.remove('status-error', 'status-processing', 'status-success');
            
            // Apply appropriate class based on state
            if (isError) {
                statusDiv.classList.add('status-error');
            } else if (isSuccess) {
                statusDiv.classList.add('status-success');
            } else if (isProcessing) {
                statusDiv.classList.add('status-processing');
            }
            
            if (message.includes('文件选择')) {
                fileInfo.classList.toggle('selected', !isError && draftFilePath);
            }
        }

        function setFilePath(path) {
            if (path) {
                draftFilePath = path;
                const filename = path.split(/[\\/]/).pop();
                fileInfo.textContent = `已选择: ${filename}`;
                fileInfo.classList.add('selected');
                updateStatus('文件已选择，请配置参数并执行操作。', false, false, true);
                applyButton.disabled = false;
                deleteButton.disabled = false;
            } else {
                draftFilePath = null;
                fileInfo.textContent = '未选择文件';
                fileInfo.classList.remove('selected');
                updateStatus('文件选择已取消或失败。', true);
                applyButton.disabled = true;
                deleteButton.disabled = true;
            }
        }
        
        function toggleParamSections() {
            const selectedEffect = document.querySelector('input[name="effect-type"]:checked').value;
            Object.values(paramSections).forEach(section => section.classList.add('hidden'));
            if (paramSections[selectedEffect]) {
                paramSections[selectedEffect].classList.remove('hidden');
            }
        }

        effectTypeRadios.forEach(radio => radio.addEventListener('change', toggleParamSections));
        
        selectFileButton.addEventListener('click', () => {
            updateStatus('等待用户选择目录...', false, true);
            applyButton.disabled = true;
            deleteButton.disabled = true;
            window.pywebview.api.trigger_directory_dialog().catch(e => {
                updateStatus(`打开目录对话框失败: ${e}`, true);
            });
        });

        applyButton.addEventListener('click', async () => {
            if (!draftFilePath) {
                updateStatus('错误：请先选择剪映草稿目录。', true);
                return;
            }

            const effectType = document.querySelector('input[name="effect-type"]:checked').value;
            const alignAudio = alignAudioImageCheckbox.checked;
            
            let params = { 
                effect_type: effectType, 
                align_audio_image: alignAudio, 
                file_path: draftFilePath 
            };

            try {
                if (effectType === 'zoom') {
                    params.scale_percentage = Number.parseInt(zoomScaleInput.value);
                } else if (effectType === 'top_bottom') {
                    params.scale_percentage = Number.parseInt(tbScaleInput.value);
                    params.y1_px = parseInt(tbY1Input.value);
                    params.y2_px = parseInt(tbY2Input.value);
                } else if (effectType === 'left_right') {
                    params.scale_percentage = Number.parseInt(lrScaleInput.value);
                    params.x1_px = parseInt(lrX1Input.value);
                    params.x2_px = parseInt(lrX2Input.value);
                } else if (effectType === 'random') {
                    params.scale_percentage = Number.parseInt(randScaleInput.value);
                    params.x1_px = parseInt(randX1Input.value);
                    params.x2_px = parseInt(randX2Input.value);
                    params.y1_px = parseInt(randY1Input.value);
                    params.y2_px = parseInt(randY2Input.value);
                }

                if (params.scale_percentage !== undefined && (isNaN(params.scale_percentage) || params.scale_percentage < 1)) {
                     updateStatus('错误：缩放倍数必须是大于0的数字。', true); return;
                }
                 if ((effectType === 'top_bottom' || effectType === 'random') && (isNaN(params.y1_px) || isNaN(params.y2_px)) ){
                      updateStatus('错误：上下移动的位置参数必须是有效的数字。', true); return;
                 }
                 if ((effectType === 'left_right' || effectType === 'random') && (isNaN(params.x1_px) || isNaN(params.x2_px)) ){
                     updateStatus('错误：左右移动的位置参数必须是有效的数字。', true); return;
                 }

                updateStatus('正在处理关键帧...', false, true);
                applyButton.disabled = true;
                deleteButton.disabled = true;

                console.log("Sending params to Python:", params);
                const response = await window.pywebview.api.apply_keyframes(params);
                
                if (response.success) {
                    updateStatus(response.message || '关键帧应用成功！', false, false, true);
                } else {
                    updateStatus(response.message || '关键帧应用失败。', true);
                }
            } catch (e) {
                updateStatus(`处理关键帧时出错: ${e}`, true);
            } finally {
                if(draftFilePath) {
                    applyButton.disabled = false;
                    deleteButton.disabled = false;
                }
            }
        });

        deleteButton.addEventListener('click', async () => {
            if (!draftFilePath) {
                updateStatus('错误：请先选择剪映草稿目录。', true);
                return;
            }
            updateStatus('正在删除关键帧...', false, true);
            applyButton.disabled = true;
            deleteButton.disabled = true;
            try {
                const response = await window.pywebview.api.delete_all_keyframes({file_path: draftFilePath});
                if (response.success) {
                    updateStatus(response.message || '所有关键帧已删除。', false, false, true);
                } else {
                    updateStatus(response.message || '删除关键帧失败。', true);
                }
            } catch (e) {
                updateStatus(`删除关键帧时出错: ${e}`, true);
            } finally {
                 if(draftFilePath) {
                    applyButton.disabled = false;
                    deleteButton.disabled = false;
                }
            }
        });
        
        function pythonUpdateStatus(message, isError = false) {
            updateStatus(message, isError, false, !isError);
        }

        window.setFilePath = setFilePath;
        window.pythonUpdateStatus = pythonUpdateStatus;

        toggleParamSections(); 
        applyButton.disabled = true;
        deleteButton.disabled = true;
        updateStatus('请点击上方按钮选择剪映草稿目录。');
    </script>
</body>
</html>
